package com.wanxi.step07test.filter;

import com.wanxi.step07test.model.SUser;
import com.wanxi.step07test.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT登录授权过滤器
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.tokenHeader}")//Authorization
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;//bearer

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String uri = request.getRequestURI();

//        String[] whiteUri = {"/login", "/code"};
//        for (String w : whiteUri
//        ) {
//            if (uri.endsWith(w)) {
//                chain.doFilter(request, response);
//                return;
//            }
//        }

       if (uri.endsWith("/login")||uri.endsWith("/code")||uri.endsWith("/upload")) {
            chain.doFilter(request, response);
            return;
        }

//        //放行OPTIONS请求
//        if (request.getMethod().equals("OPTIONS")) {
//            response.setHeader("Access-Control-Allow-Origin", "*");
//            response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
//            response.setHeader("Access-Control-Max-Age", "3600");
//            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
//            return;
//        }

        //从 header  中获取 Authorization
        String authHeader = request.getHeader(this.tokenHeader);

        // 没有头信息
        if (authHeader == null) {
            chain.doFilter(request, response);
            return;
        }
        // 判断 authHeader  不为空  并且以 bearer 开头
        boolean isAuthorizationHeader = StringUtils.startsWithIgnoreCase(authHeader, this.tokenHead);
        if (!isAuthorizationHeader) {
            chain.doFilter(request, response);
            return;
        }
        //截取 bearer 后面的字符串  并且 两端去空格（获取token）
        String authToken = authHeader.substring(this.tokenHead.length()).trim();// The part after "Bearer "

        // 获取token的用户名
        String username = jwtTokenUtil.getUserNameFromToken(authToken);

        //验证redis里用户是否已经登录过期（12小时）
        String userKey = "user:" + username;
        SUser sUser = (SUser) redisTemplate.opsForValue().get(userKey);
        if(sUser==null){
            chain.doFilter(request, response);
            return;
        }



        LOGGER.info("checking username:{}", username);
        // 用户名不为空  并且SecurityContextHolder.getContext()  存储 权限的容器中没有相关权限则继续
        boolean isNotAuthentication = SecurityContextHolder.getContext().getAuthentication() == null;
        if (username != null && isNotAuthentication) {
            //从数据库读取用户信息
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);


            //验证token，是否刷新token
            if(jwtTokenUtil.refreshToken(authToken,userDetails)){

//            //校验token
//            if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                // 一个实现的带用户名和密码以及权限的Authentication(spring 自带的类)
                UsernamePasswordAuthenticationToken authentication = null;
                authentication = new UsernamePasswordAuthenticationToken(userDetails,
                        null, userDetails.getAuthorities());
                // 从HttpServletRequest 对象，创建一个WebAuthenticationDetails对象
                WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request);
                //设置details
                authentication.setDetails(details);
                LOGGER.info("authenticated user:{}", username);
                //存入本线程的安全容器   在访问接口拿到返回值后 要去主动清除 权限，避免干扰其他的线程
                //SecurityContextHolder会把authentication放入到session里，供后面使用
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        chain.doFilter(request, response);

    }
}